import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Does the calculation of likelihood weighting
 * 
 * Important for Class
 * Math.random gives 0<=x<1, so the border has to be strict<
 * @author walonka, zyner
 *
 */
public class Main {
	/*
	 * E(Sprinkler)=0.1*1+0.5*0
	 * E(Rain)=0.8*1+0.2*0
	 * E(WetGRass)=Sum(P(X_i)*X_i) = P(tt)*0.99+P(tf)*0.9+P(ft)*0,9
	 * E(WetGRass^2)=Sum(P(X_i)*X_i^2) = P(tt)*0.99^2+P(tf)*0.9^2+P(ft)*0,9^2
	 * Var(WetGrass)=(E(WetGRass^2)-E(WetGRass)^2)
	 * 
	 * P(tt) = 1*0.1*0.99 =0.099
	 * P(tf) = 1*0.1*0.90 =0.090
	 * P(ft) = 1*0.5*0.09 =0.495
	 * P(ff) = 1*0.5*0.00 =0.00
	 * => E(X) =  (0.099+0.09+0.495+0)/4=0.171
	 * => E^2(X) = 0.029241
	 * 
	 * E(X^2):
	 * P(tt) = 1*0.1*0.99^2 =0.09801
	 * P(tf) = 1*0.1*0.90^2 =0.081
	 * P(ft) = 1*0.5*0.09^2 =0.4455
	 * P(ff) = 1*0.5*0.00 =0.00
	 * E(X^2)= (0.09801+0.081+0.4455+0)/4=0.1561275
	 * 
	 * Var(WetGrass)=0.1561275-0.171^2=0.1268865
	 * 
	 * The Variance is constant, this can't and won't change
	 * Only the mean variable will change
	 */
	

	
	/**
	 * This Method returns true if it's clody and false if it isn't 
	 * the probability for each is 0.5
	 * @return
	 */
	private static boolean isCloudy(){
		/*
		 * cloudy:
		 * true=0.5
		 * false=0.5
		 */
		if(Math.random()<0.5){
			return true;
		}
		else return false;
	}


	/**
	 * Is it raining?
	 * @param cloudy is it cloudy?
	 * @return raining?
	 */
	private static boolean isRain(boolean cloudy){
		/*
		 * rain:
		 * true=0.8
		 * false=0.2
		 */
		if(cloudy){
			if(Math.random()<0.8){
				return true;
			}
			else return false;
		}else{ //not cloudy = 20% true
			if(Math.random()<0.2){
				return true;
			}
			else return false;
		}
	}
	
	
	/**
	 * Method to do the likelihood weight calculation
	 * @param samples amount of samples
	 * @return
	 */
	public static double doIt(int samples){
		int runs = samples;
		//initial weight vector
		double weightSum =0;
		double cloudySum = 0;
		double trueSum = 0;
		double falseSum = 0;
		
		for(int run=0; run<runs; run++){

			boolean sprinkler = true;
			boolean cloudy = isCloudy();
			boolean rain = isRain(cloudy);
			double weight =1;
			
			//I'm not sure if this part is how it should be
			//does it really split here?
			//don't we assume that it will always be the way we want and change after that
			// I think it always has to be the left way
			//TODO
			if(cloudy){ //change weight according to sprinkler
				weight*=0.1;
			} else{
				weight*=0.5;
			}
			
			//Sprinker always true, whole table included for completeness
			if((sprinkler==true)&(rain==true)){
				weight*=0.99;
			}
			else if((sprinkler==true)&(rain==false)){
				weight*=0.90;
			}
			else if((sprinkler==false)&(rain==true)){
				weight*=0.90;
			}
			else if((sprinkler==false)&(rain==false)){
				weight*=0.00;	
			}
			weightSum+=weight;
			if(cloudy)
				trueSum+=weight;
			else
				falseSum+=weight;
		}
		weightSum/=runs; //Normalize it
		//The weight is not what we want to return. We want to return P(cloudy) modified by a weight.
		//Therefore we need to compare the true and false samples
		cloudySum/=runs;
		return (trueSum/(trueSum+falseSum)); //return it
	}
	
	/**
	 * Method to do 1000 runs with n sambles
	 * @param samples amount of samples
	 * @return
	 */
	private static double[] thousandRuns(int samples){
		double[] results= new double[1002];
		for (int i=0; i<1000; i++){
			results[i]=doIt(samples);
		}
		
		/*
		 * Calculate the mean value and store it at position 1000
		 */
		double tmp= 0;
		for (int i=0; i<results.length-1;i++){
			tmp+=results[i];
		}
		results[1000]=tmp/1000; //mean value
		
		/*
		 * Calculate the mean variance value and store it at position 1001
		 */
		double varIterSum = 0;
		for (int i=0; i<results.length-1;i++){
			varIterSum+=Math.pow(results[i]-results[1000],2);
		}
		results[1001]=varIterSum/1000; //mean value

		return results;
	}

	/**
	 * Gives the CommandLineInterface
	 * @param args
	 */
	public static void main(String[] args) {
		BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Welcome");
		while(true){
			try{
				System.out.println("Do you want to do 1000 runs or only 1 run? \n Enter 1 for only 1 run or 2 for 1000 runs. You can leave the program with 0.");
				int decision = Integer.parseInt(console.readLine());
				if (decision==0){
					break;
				}
				else if(decision==1){
					System.out.println("Please enter the number of samples");
					int samples = Integer.parseInt(console.readLine());
					System.out.println("P(cloudy | sprinkler, wetgrass) "+doIt(samples));
				}
				else if(decision==2){
					System.out.println("Please enter the number of samples");
					int samples = Integer.parseInt(console.readLine());
					System.out.println("The variance is "+thousandRuns(samples)[1001]+" and after 1000 runs the mean value of P(cloudy | sprinkler, wetgrass) is "+thousandRuns(samples)[1000]);
				}
			}
			catch(Exception e){
				System.out.println("There was an error with the input, please try again!");
			}
			
		}
	}

}
